package com.ccteam.admin.viewmodels.common

import android.app.Application
import android.net.Uri
import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.*
import cn.hutool.core.util.IdUtil
import com.ccteam.admin.repositories.UploadAdminRepository
import com.ccteam.admin.utils.ErrorMessage
import com.ccteam.admin.utils.Event
import com.ccteam.admin.utils.parseMimeType
import com.ccteam.admin.view.bean.UploadResult
import com.ccteam.admin.view.fragments.common.UploadFragment
import com.ccteam.admin.vo.Resource
import com.ccteam.network.ApiError
import com.orhanobut.logger.Logger
import com.qiniu.android.storage.UpCancellationSignal
import com.qiniu.android.storage.UploadManager
import com.qiniu.android.storage.UploadOptions
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import javax.inject.Inject
import kotlin.math.min

/**
 * @author Xiaoc
 * @since 2021/3/10
 *
 * 上传文件ViewModel
 */
@HiltViewModel
class UploadViewModel @Inject constructor(
    application: Application,
    private val uploadManager: UploadManager,
    private val uploadRepository: UploadAdminRepository,
    savedStateHandle: SavedStateHandle
): AndroidViewModel(application) {

    private val _uploadProgress = MutableLiveData(0)
    val uploadProgress: LiveData<Int> get() = _uploadProgress

    private val _uploading = MutableLiveData(false)
    val uploading: LiveData<Boolean> get() = _uploading

    private val _isSuccess = MutableLiveData<Event<UploadMessage>>()
    val isSuccess: LiveData<Event<UploadMessage>> get() = _isSuccess

    private val _errorMessage = MutableLiveData<Event<ErrorMessage>>()
    val errorMessage: LiveData<Event<ErrorMessage>> get() = _errorMessage

    private val _selectUri = MutableLiveData(Uri.EMPTY)
    val selectUri: LiveData<Uri> get() = _selectUri

    private val type: Int? = savedStateHandle.get<Int>("uploadType")

    @Volatile
    private var shouldCancel: Boolean = false

    fun setSelectUri(fileUri: Uri){
        _selectUri.value = fileUri
    }

    fun uploadFile(){
        val application = getApplication<Application>()
        if(selectUri.value == Uri.EMPTY){
            _errorMessage.value = Event(ErrorMessage(ApiError.unknownCode,"文件Uri不存在"))
            return
        }
        if(type == null){
            _errorMessage.value = Event(ErrorMessage(ApiError.unknownCode,"上传类型未知，请重试"))
            return
        }

        viewModelScope.launch {
            _uploading.value = true

            val result = if(type == UploadFragment.PHOTO_UPDATE_TYPE){
                uploadRepository.getImageToken()
            } else {
                uploadRepository.getMediaToken()
            }
            // 检测token是否获取成功
            if(result !is Resource.Success || result.data.isNullOrEmpty()){
                _uploading.value = false
                _errorMessage.value = Event(ErrorMessage(ApiError.unknownCode,"请求Token失败"))
                return@launch
            }

            val token = result.data

            val file = DocumentFile.fromSingleUri(application.applicationContext, selectUri.value!!)
            if(file == null){
                _uploading.value = false
                _errorMessage.value = Event(ErrorMessage(ApiError.unknownCode,"文件信息不存在"))
                return@launch
            }

            viewModelScope.launch(Dispatchers.IO){

                /**
                 * 生成文件名，并执行上传操作
                 */
                val mimeType = file.type
                val fileName = IdUtil.simpleUUID() + "." + file.parseMimeType()
                Logger.d("fileName:${fileName}")

                /**
                 * 获得该文件的字节数组
                 */
                val data = application.contentResolver.openInputStream(selectUri.value!!)?.readBytes()
                if(data == null){
                    _uploading.postValue(false)
                    _errorMessage.value = Event(ErrorMessage(ApiError.unknownCode,"文件信息不存在"))
                } else {
                    uploadManager.put(data,
                        fileName, token, { key, info, response ->
                            _uploading.value = false
                            Logger.d("Key:$key -- info:$info -- $response")
                            if(info.isOK){
                                _isSuccess.value = Event(UploadMessage(true,
                                    UploadResult(type,response.getString("data"))))
                            } else {
                                _errorMessage.value = Event(ErrorMessage(info.statusCode,info.error))
                            }
                        },
                        UploadOptions(null,mimeType,false, { key, percent ->
                            Logger.d("进度：$percent Key:$key")
                            _uploadProgress.value = (percent * 100).toInt()
                        }, UpCancellationSignal {
                            return@UpCancellationSignal shouldCancel
                        })
                    )
                }
            }
        }

    }

    override fun onCleared() {
        super.onCleared()
        shouldCancel = true
    }

    data class UploadMessage(
        val success: Boolean,
        val result: UploadResult
    )

}